local japi = require 'jass.japi'
local md5 = japi.md5

local filter = {}
setmetatable(filter, filter)

ac.filter = filter

-- 单例表
local instances = {}

-- 操作
local operators = {
    ['>'] = function(a, b)
        if a and b then 
            return a > b
        end 
    end,
    ['<'] = function(a, b)
        if a and b then 
            return a < b
        end 
    end,
    ['>='] = function(a, b)
        if a and b then 
            return a >= b
        end 
    end,
    ['<='] = function(a, b)
        if a and b then 
            return a <= b
        end 
    end,
    ['='] = function(a, b)
        if a and b then 
            return a == b
        end 
    end,
    ['&'] = function(a)
        if a then 
            return (a > 0) 
        end 
    end,
}

function filter.parser(str)
    if type(str) ~= 'string' then return end;
    local ins = setmetatable({
        _keys = {},
        _mate = {},
    }, filter)
    for chunk in str:gmatch('[^;]+') do 
        local key, op, value = chunk:match("([^<^>^=^&]+)([^%d]+)([%d]*)$")
        if key and op and operators[op] then 
            ins._keys[key] = true
            table.insert(ins._mate, {key, op, tonumber(value) or 0})
        end 
    end 
    return ins
end

function filter:__call(str)
    if type(str) ~= 'string' then return end;
    local name = md5(str)
    local ins = instances[name]
    if not ins then 
        ins = filter.parser(str)
        instances[name] = ins
    end 
    return ins
end

local api = {}
filter.__index = api

-- 判断一个表是否通过检验
function api:check(data)
    if not data then return false end
    local bool = true
    local mate = self._mate
    for i = 1,#mate do 
        local key, op, value = table.unpack(mate[i])
        if not operators[op](data[key], value) then 
            bool = false
            break 
        end
    end 
    return bool
end 

function api:format(data)
    local buff = {'|cffffcc00需要:|r',}
    local mate = self._mate
    for i = 1,#mate do 
        local key, op, value = table.unpack(mate[i])
        local bool = data and operators[op](data[key], value) or false
        local text = '|cffff4444 - %s|r'
        if bool then 
            -- text = '|cff00ff00√|r|cffffcc00 - %s|r'
            -- text = '|cffffcc00 - %s|r'
        else 
            -- text = '|cffff0000×|r|cffc0c0c0 - %s|r'
            -- text = '|cffc0c0c0 - %s|r'
            if op == '&' then 
                buff[#buff+1] = text:format(key)
            else
                buff[#buff+1] = text:format(("%s %s%d"):format(key, op, value))
            end
        end 
    end 
    return table.concat(buff, '\r\n')
end

function api:reference(name)
    if not name then return end;
    return self._keys[name]
end 

return filter